﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace OpenSearchExplorer
{
    /// <summary>
    /// Interaction logic for OSDDDisplayPage.xaml
    /// </summary>
    public partial class OSDDDisplayPage : Page
    {
        private OpenSearch.Osdd.IOpenSearchDescriptionDocument osdd = null;

        public OSDDDisplayPage()
        {
            InitializeComponent();
        }

        public bool getOsdd(Uri uri)
        {
            try
            {
                System.Net.WebRequest req = System.Net.WebRequest.Create(uri);
                System.Net.HttpWebResponse resp = req.GetResponse() as System.Net.HttpWebResponse;
                System.IO.StreamReader respStreamReader = new System.IO.StreamReader(resp.GetResponseStream());
                string osddString = respStreamReader.ReadToEnd();
                setupRawViewOfOsddContent(osddString);
                setupProcessedViewofOsddContent(osddString);
                OSDDDisplayLabel.Text = "OpenSearch Description Document from " + uri.ToString();
                return true;
            }
            catch (System.Net.WebException ex)
            {
                System.Windows.MessageBox.Show(ex.Message, "Network Problem");
                return false;
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message, "Problem");
                return false;
            }
        }

        private void setupProcessedViewofOsddContent(string osddString)
        {
            osdd = new OpenSearch.Osdd.OpenSearchDescriptionDocument(osddString);
            osddTextBlock.Text = "";
            addText("Short Name", osdd.ShortName);
            addText("Long Name", osdd.LongName);
            addText("Description", osdd.Description);
            addTextList("Tags", osdd.Tags);
            addText("Contact", osdd.Contact);
            addText("Queries", osdd.Queries.Count.ToString());
            foreach (OpenSearch.Osdd.Query query in osdd.Queries)
            {
                addQuery(query);
            }
            addText("Images", osdd.Images.Count.ToString());
            foreach (OpenSearch.Osdd.Image image in osdd.Images)
            {
                addImage(image);
            }
            addText("URLs", osdd.Urls.Count.ToString());
            foreach (OpenSearch.Osdd.Url url in osdd.Urls)
            {
                addUrl(url);
            }
            addText("Developer", osdd.Developer);
            addText("Attribution", osdd.Attribution);
            addText("Syndication Right", osdd.SyndicationRight.ToString());
            addText("Adult Content", (osdd.AdultContent ? "yes" : "no"));
            addTextList("Languages", osdd.Languages);
            addTextList("Input Encodings", osdd.InputEncodings);
            addTextList("Output Encodings", osdd.OutputEncodings);
        }

        private void addImage(OpenSearch.Osdd.Image image)
        {
            osddTextBlock.Inlines.Add(new Run("\t" + image.Uri + ":" + Environment.NewLine));
            string width = image.Width.ToString();
            string height = image.Height.ToString();
            addParameterIfNotNull("Size", (width + " by " + height));
            addParameterIfNotNull("MIME type", image.MimeType);
            addRenderedImage(image);
        }

        private void addRenderedImage(OpenSearch.Osdd.Image image)
        {
            Image renderedImage = new Image();
            BitmapDecoder decoder = BitmapDecoder.Create(image.Uri, BitmapCreateOptions.None, BitmapCacheOption.Default);
            renderedImage.Width = image.Width;
            renderedImage.Height = image.Height;
            renderedImage.Source = decoder.Frames[0];
            renderedImage.Visibility = System.Windows.Visibility.Visible;
            InlineUIContainer uiContainer = new InlineUIContainer(renderedImage);
            osddTextBlock.Inlines.Add(new Run("\t\t"));
            osddTextBlock.Inlines.Add(uiContainer);
            osddTextBlock.Inlines.Add(new Run(Environment.NewLine));
        }

        private void addTextList(string label, ICollection<string> parameterCollection)

        {
            if (parameterCollection != null)
            {
                addText(label, string.Join(", ", parameterCollection));
            }
        }

        private void addUrl(OpenSearch.Osdd.Url url)
        {
            osddTextBlock.Inlines.Add(new Bold(new Run("\tTemplate: ")));
            Run templateRun = new Run(url.Template.ToString());
            if (shouldBeHyperlinked(url))
            {
                Hyperlink templateHyperlink = new Hyperlink(templateRun);
                templateHyperlink.Click += new RoutedEventHandler(templateHyperlink_Click);
                templateHyperlink.Tag = url;
                osddTextBlock.Inlines.Add(templateHyperlink);
            }
            else
            {
                osddTextBlock.Inlines.Add(templateRun);
            }
            osddTextBlock.Inlines.Add(new Run(Environment.NewLine));
            addParameterIfNotNull("Index offset", url.IndexOffset.ToString());
            addParameterIfNotNull("MIME type", url.MimeType);
            addParameterIfNotNull("Relation", url.Relation);
            addParameterIfNotNull("Page offset", url.PageOffset.ToString());
        }

        private static bool shouldBeHyperlinked(OpenSearch.Osdd.Url url)
        {
            return (url.Relation == "results");
        }

        private void addQuery(OpenSearch.Osdd.Query query)
        {
            osddTextBlock.Inlines.Add(new Run("\t" + query.Role + ":" + Environment.NewLine));
            foreach (OpenSearch.NameSpacedParameter queryParam in query.ExtendedAttributes)
            {
                string queryLabel = null;
                if (queryParam.Namespace == OpenSearch.Constants.NSOpenSearch)
                {
                    if (queryParam.Parameter == "role")
                    {
                        // nothing, we dealt with that in the header
                    }
                    else
                    {
                        queryLabel = queryParam.Parameter;
                    }
                }
                else
                {
                    queryLabel = queryParam.Parameter + " [" + queryParam.Namespace + "]";
                }
                if (queryLabel != null)
                {
                    addParameterIfNotNull(queryLabel, query.GetExtendedAttribute(queryParam.Namespace, queryParam.Parameter));
                }
            }
        }

        private void addParameterIfNotNull(string label, string parameterValue)
        {
            if (! string.IsNullOrEmpty(parameterValue))
            {
                osddTextBlock.Inlines.Add(new Run("\t\t" + label + ": " + parameterValue + Environment.NewLine));
            }
        }

        private void addText(string label, string value)
        {
            osddTextBlock.Inlines.Add(new Bold(new Run(label + " : ")));
            osddTextBlock.Inlines.Add(new Run(value));
            osddTextBlock.Inlines.Add(Environment.NewLine);
        }

        private void setupRawViewOfOsddContent(string osddString)
        {
            osddRawView.Document.Text = osddString;
            enableXmlFoldingForRawView();
            osddRawView.IsReadOnly = true;
        }

        private void enableXmlFoldingForRawView()
        {
            ICSharpCode.AvalonEdit.Folding.FoldingManager foldingManager = ICSharpCode.AvalonEdit.Folding.FoldingManager.Install(osddRawView.TextArea);
            ICSharpCode.AvalonEdit.Folding.XmlFoldingStrategy foldingStrategy = new ICSharpCode.AvalonEdit.Folding.XmlFoldingStrategy();
            foldingStrategy.UpdateFoldings(foldingManager, osddRawView.Document);
        }

        private void templateHyperlink_Click(object sender, RoutedEventArgs e)
        {
            Hyperlink senderHyperlink = sender as Hyperlink;
            if (senderHyperlink == null)
            {
                return;
            }
            OpenSearch.Osdd.Url url = senderHyperlink.Tag as OpenSearch.Osdd.Url;
            if (url == null)
            {
                return;
            }
            TemplateCompletionPage templateCompletionPage = new TemplateCompletionPage();
            templateCompletionPage.setUrl(url);
            this.NavigationService.Navigate(templateCompletionPage);
        }
    }
}
